package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.sys.modules.models.SysParam;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.app.user.modules.models.GroupInfo;
import cn.wizzer.app.user.modules.models.GroupLog;
import cn.wizzer.app.user.modules.models.GroupLogUserRelation;
import cn.wizzer.app.user.modules.models.GroupMember;
import cn.wizzer.app.user.modules.models.enums.MsgStatusEnum;
import cn.wizzer.app.user.modules.models.enums.MsgTypeEnum;
import cn.wizzer.app.user.modules.models.enums.OprTypeEnum;
import cn.wizzer.app.user.modules.models.vo.GroupLogVo;
import cn.wizzer.app.user.modules.services.GroupInfoService;
import cn.wizzer.app.user.modules.services.GroupLogService;
import cn.wizzer.app.user.modules.services.GroupLogUserRelationService;
import cn.wizzer.app.user.modules.services.GroupMemberService;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Times;
import org.nutz.trans.Trans;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = GroupLogService.class)
public class GroupLogServiceImpl extends BaseServiceImpl<GroupLog> implements GroupLogService {
    public GroupLogServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;
    @Inject
    private GroupMemberService groupMemberService;
    @Inject
    private GroupLogUserRelationService groupLogUserRelationService;
    @Inject
    private GroupInfoService groupInfoService;
    @Inject
    @Reference
    private SysParamService sysParamService;

    @Override
    public Pagination listPage(Integer pageNumber, Integer pageSize, String groupId, String userId) {
        Sql sql = Sqls.create("SELECT gl.id, gl.groupId, gl.ctAt, gl.userId, gl.oprType, gl.msgType, gl.content, " +
                "u.nickName, u.headPicture, glur.status as msgStatus " +
                "FROM group_log_user_relation glur " +
                "LEFT JOIN group_log gl ON gl.id = glur.groupLogId " +
                "LEFT JOIN `user` u ON u.id = gl.userId " +
                "$condition ");
        Sql countSql = Sqls.create("SELECT COUNT(1) FROM group_log_user_relation glur $condition ");
        Cnd cnd = Cnd.where("glur.groupId", "=", groupId).and("glur.userId", "=", userId);

        sql.setCondition(cnd);
        sql.appendSourceSql("ORDER BY gl.ctAt DESC ");
        countSql.setCondition(cnd);
        return dbService.listPage(GroupLogVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    @Aop(TransAop.READ_COMMITTED)
    @Override
    public Map<String, Object> groupSend(String sendUserId, String groupId, String content, MsgTypeEnum type, OprTypeEnum oprType, boolean isDel) {
        GroupInfo groupInfo = groupInfoService.fetch(groupId);
        if (groupInfo == null) {
            Result.breakWith("请选择群进行发言");
        }
        if (!groupInfo.getMasterId().equals(sendUserId) && groupInfo.isDisabled()) {
            Result.breakWith("群已禁言，无法发言");
        }
        if (!isDel) {
            //判断自己是否还在群里
            GroupMember groupMember = groupMemberService.fetch(Cnd.where("groupId", "=", groupId).and("userId", "=", sendUserId).and("delFlag", "=", 0));
            if (groupMember == null) {
                Result.breakWith("你已不在群里");
            }
        }
        //创建群消息记录
        GroupLog create = GroupLog.create(groupId, sendUserId, oprType, type, content);
        GroupLog groupLog = this.insert(create);

        List<GroupLogUserRelation> groupLogUserRelations = new ArrayList<>();
        //创建用户读取群消息记录
        groupLogUserRelations.add(GroupLogUserRelation
                .create(groupId, groupLog.getId(), sendUserId, MsgStatusEnum.READ));
        //获取所有群成员(不包含自己)
        List<GroupMember> groupMembers = groupMemberService.query(Cnd.where("groupId", "=", groupId).and("delFlag", "=", 0).and("userId", "!=", sendUserId));
        for (GroupMember member : groupMembers) {
            //创建用户读取群消息记录
            groupLogUserRelations.add(GroupLogUserRelation
                    .create(groupId, groupLog.getId(), member.getUserId(), MsgStatusEnum.UN_READ));
            //未读消息记录加1
            Trans.exec(Connection.TRANSACTION_READ_COMMITTED, () -> {
                groupMemberService.update(Chain.make("unReadCount", member.getUnReadCount() + 1), Cnd.where("id", "=", member.getId()));
            });
        }
        groupLogUserRelationService.insert(groupLogUserRelations);

        Map<String, Object> map = new HashMap<>();

        map.put("groupLog", groupLog);
        map.put("groupLogUserRelations", groupLogUserRelations);
        return map;
    }

    @Override
    public void delLogJob() {
        SysParam sysParam = sysParamService.fetch();
        //全局参数获取群聊记录保存天数
        Integer keepDayNumber = sysParam.getGroupLogKeepDayNumber();
        //天数大于0时计算删除一定时间前的记录
        if(keepDayNumber > 0){
            //保存时间
            long keepTimestamp = keepDayNumber * 24 * 60 * 60;
            //保存开始时间 = 当前时间 - 保存时间
            long keepStartTime = Times.getTS() - keepTimestamp;
            //查询保存开始时间之前的记录后删除记录
            List<GroupLog> groupLogs = this.query(Cnd.where("ctAt", "<=", keepStartTime));
            for (GroupLog groupLog : groupLogs) {
                //清空该聊天记录关联的用户已读未读记录
                groupLogUserRelationService.clear(Cnd.where("groupLogId", "=", groupLog.getId()));
                //删除该聊天记录
                this.delete(groupLog.getId());
            }
        }
    }
}
